<template>
	<scroll-view class="zm-tabs-container" scroll-x="true" :show-scrollbar='false' scroll-with-animation
		:scroll-left="scrollLeft" @scroll="zmScroll" :style='styleObject'>
		<view class="zm-tabs-scroll-container">
			<view v-for="(item,index) in list" class="zm-tabs-item" :key="item.key"
				@click="onchange($event,item.key,item.disabled)">
				<view class="zm-tabs-tab"
					:class="{'zm-active-tab':activeKey == item.key , 'zm-tabs-tab-disabled':item.disabled} ">
					{{item.title}}
				</view>
			</view>

			<view :animation="zmIndicatorAnimatorData" class="zm-indicator"></view>
		</view>
	</scroll-view>
</template>
<script setup lang="ts">
	import { onMounted, ref, getCurrentInstance, reactive, computed, watchEffect, watch } from "vue"

	interface ITabItem {
		key : string,
		title : string,
		disabled ?: boolean
	}
	
	const emit = defineEmits<{
		(event:'change',key:string): void
	}>()

	const props = withDefaults(defineProps<{
		list : ITabItem[]
		// 当前激活 tab 面板的 key
		activeKey ?: string,
		// 激活 tab 下划线的模式
		activeLineMode ?: 'auto' | 'full' | 'fixed',
		// 初始化选中面板的 key，如果没有设置 activeKey
		defaultActiveKey ?: string,
		// 切换面板的回调
		change ?: (key : string) => void,
		// 自定义选中项下划线长度 只有设置 activeLineMode 为 fixed 时才生效
		customIndictorWidth ?: number,
		//  指示器切换动画时间
		animationDuration ?: number,
		// 选中的tab项自动出现
		activeTabAutoShow ?: boolean,
		style ?: {

			/// 激活 tab 下划线的颜色
			"--active-line-color" ?: string,
			/// 激活 tab 下划线的高度 
			"--active-line-height" ?: string,
			/// 激活 tab 下划线的圆角
			"--active-line-border-radius" ?: string,
			/// 激活 tab 选项文字颜色
			"--active-title-color" ?: string,
			/// 选项卡文字的大小
			"--title-font-size" ?: string,
		}
	}>(), {
		activeLineMode: 'auto',
		animationDuration: 300,
		activeTabAutoShow: true,
		customIndictorWidth: 30
	});

	const styleObject = computed(() => {
		return ({
			"--active-line-color": props.style?.["--active-line-color"] || '#1677ff',
			"--active-line-height": props.style?.["--active-line-height"] || '2px',
			"--active-line-border-radius": props.style?.["--active-line-border-radius"] || '2px',
			"--active-title-color": props.style?.["--active-title-color"] || '#1677ff',
			"--title-font-size": props.style?.["--title-font-size"] || '17px',
		})
	});

	const instance = getCurrentInstance();
	let zmIndicatorAnimatorData = ref({});
	let zmIndicatorAnimator : UniApp.Animation = null;
	let halfPageWidth = 0;
	const scrollLeft = ref(0);
	let maxScrollLeft = 0;
	let zmTabMounted = ref(false);
	let zmTabItemNodes : (UniApp.NodeInfo & ITabItem)[] = [];

	const activeKey = ref(props.activeKey);


	const zmScroll = (e) => {
		scrollLeft.value = e.detail.scrollLeft;
	}

	const computeTabItemNodes = async (list : ITabItem[]) => {
		return new Promise((resolve, reject) => {
			const tabItems = list;
			const query = uni.createSelectorQuery().in(instance);



			let nodeName = ".zm-tabs-tab";

			let width = 0

			if (props.activeLineMode == 'fixed' && props.customIndictorWidth) {
				width = props.customIndictorWidth;
			}


			if (props.activeLineMode == 'full') {
				nodeName = '.zm-tabs-item';
			}

			const node = query.selectAll(nodeName)

			node.boundingClientRect((res => {
				let infos = res as UniApp.NodeInfo[];
				
				zmTabItemNodes = infos.map((item, index) => {

					let itemWidth = width || item.width;
					const left = item.left + item.width / 2 - itemWidth / 2;
					
					return {
						...item,
						left,
						width: itemWidth,
						key: tabItems[index].key,
						title: tabItems[index].title
					}
				});
				const last = infos.length - 1;
				let maxWidth = 0;
				if(props.activeLineMode == 'full') {
					maxWidth = infos[last].width + infos[last].left
				}else {
					maxWidth = infos[last].width + infos[last].left +  12;
				}
				maxScrollLeft = maxWidth - halfPageWidth * 2;

				resolve(true)

			})).exec();

		})
	}


	watch(props.list, async () => {
		
		updateSource();
		
	},{ flush:'post' })

	const playTabChangeAnimation = () => {
		const index = zmTabItemNodes.findIndex(item => item.key == activeKey.value);

		const activeIndex = Math.max(index, 0);

		const animation = uni.createAnimation({
			duration: props.animationDuration || 300,
			timingFunction: 'linear'
		});

		const left = zmTabItemNodes[activeIndex].left;
		const width = zmTabItemNodes[activeIndex].width;
		zmIndicatorAnimator = animation;
		zmIndicatorAnimator.width(width).translateX(left).step()
		if (props.activeTabAutoShow) {
			scrollLeft.value = Math.min(maxScrollLeft,Math.max(0,left - halfPageWidth + width / 2));
		}
		zmIndicatorAnimatorData.value = zmIndicatorAnimator.export();

	}
	watch(() => props.activeKey, () => {
		if(props.activeKey != activeKey.value) {
			activeKey.value = props.activeKey || props.defaultActiveKey || props.list[0].key;
			if (zmTabMounted && playTabChangeAnimation) {
				playTabChangeAnimation();
			}
		}
	});

	onMounted(() => {
		zmTabMounted.value = true;



		const instance = getCurrentInstance();
		const query = uni.createSelectorQuery().in(instance);

		let page = query.select(".zm-tabs-container");

		page.boundingClientRect(res => {
			const pageWidth = (res as UniApp.NodeInfo).width;
			halfPageWidth = pageWidth / 2;
		
			updateSource();
		}).exec()


	})



	const updateSource = async () => {
		if (props.list.length && zmTabMounted.value) {
			const result = await computeTabItemNodes(props.list);
			if (result) {

				playTabChangeAnimation();
			}
		}
	}



	const onchange = (event : any, key : string, disabled : boolean = false) => {

		if (!disabled) {
			changeKey(key);
			emit('change',key);
		}

	}

	const changeKey = (key : string) => {
		activeKey.value = key;

		playTabChangeAnimation();
	}
</script>
<style>
	.zm-tabs-container {
		width: 100vw;

	}

	.zm-tabs-scroll-container {
		display: flex;
		/* overflow-x: scroll; */
		align-items: center;
		flex-wrap: nowrap;
		position: relative;
		justify-content: flex-start;
		flex-direction: row;
		border-bottom: 1px solid #eee;
	}

	/deep/ ::-webkit-scrollbar {
		display: none;
		width: 0;
		height: 0;
		-webkit-appearance: none;
		background-color: transparent;
		color: transparent;
	}

	.zm-tabs-item {
		flex: auto;
		padding: 0 12px;

	}


	.zm-tabs-tab {
		white-space: nowrap;
		padding: 8px 0 10px;
		width: min-content;
		margin: 0 auto;
		position: relative;
		font-size: var(--title-font-size);
	}

	.zm-indicator {
		position: absolute;
		height: var(--active-line-height);
		border-radius: var(--active-line-border-radius);
		background-color: var(--active-line-color);
		bottom: 0px;
		left: 0;
		width: 100px;
	}

	.zm-active-tab {
		color: var(--active-title-color);
	}

	.zm-tabs-tab-disabled {
		opacity: .5;
		cursor: not-allowed;
	}
</style>